package mxmf.filter;

import java.security.SecureRandom;
import java.util.Base64;
import java.util.List;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import com.fasterxml.jackson.databind.ObjectMapper;

import chances.smart.commons.rest.RestResponse;
import mxmf.data.DataInfo;
import mxmf.utils.ObjectMapperHelper;

public class DataTokenInterceptor implements HandlerInterceptor {

    private String key;

    private List<String> ignorePath;

    private ObjectMapper objectMapper = ObjectMapperHelper.createObjectMapper();

    public DataTokenInterceptor(String key, List<String> ignorePath) {
        this.key = key;
        this.ignorePath = ignorePath;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler) throws Exception {
        if (StringUtils.isEmpty(this.key)) {
            return true;
        }
        if (request.getMethod().equals("OPTIONS")) {
            return true;
        }
        if (StringUtils.isEmpty(this.key)) {
            return true;
        }

        if (isIgnorePath(request.getServletPath())) {
            return true;
        }
        String dataToken = this.getDataToken(request);
        if (StringUtils.isBlank(dataToken)) {
            RestResponse result = new RestResponse(405, "date token autherror");
            response.sendError(405);
            response.getWriter().write(this.objectMapper.writeValueAsString(result));
            return false;
        } else {
            DataInfo dataInfo = createDataInfo(dataToken);
            request.setAttribute("dataInfo", dataInfo);

            return true;
        }

    }

    private boolean isIgnorePath(String servletPath) {
        return ignorePath.parallelStream().anyMatch(i -> servletPath.startsWith("/" + i));
    }

    private DataInfo createDataInfo(String dataToken) throws Exception {
        byte[] body = Base64.getDecoder().decode(dataToken);
        byte[] source = decrypt(body, this.key);
        return objectMapper.readValue(source, DataInfo.class);
    }

    private String getDataToken(HttpServletRequest request) {
        return request.getHeader("dataToken");
    }

    public static byte[] decrypt(byte[] src, String password) throws Exception {
        // DES算法要求有一个可信任的随机数源
        SecureRandom random = new SecureRandom();
        // 创建一个DESKeySpec对象
        DESKeySpec desKey = new DESKeySpec(password.getBytes());
        // 创建一个密匙工厂
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        // 将DESKeySpec对象转换成SecretKey对象
        SecretKey securekey = keyFactory.generateSecret(desKey);
        // Cipher对象实际完成解密操作
        Cipher cipher = Cipher.getInstance("DES");
        // 用密匙初始化Cipher对象
        cipher.init(Cipher.DECRYPT_MODE, securekey, random);
        // 真正开始解密操作
        return cipher.doFinal(src);
    }
}
